package org.xbzheng.restful_study.security;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.xbzheng.restful_study.model.Resources;
import org.xbzheng.restful_study.model.Role;
import org.xbzheng.restful_study.service.RoleService;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * 加载资源与权限的对应关系
 */
@Component("customFilterInvocationSecurityMetadataSource")
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private static final Logger LOG = LoggerFactory.getLogger(CustomFilterInvocationSecurityMetadataSource.class);

    @Autowired
    private RoleService roleService;
    private Map<String, Collection<ConfigAttribute>> resourceMap = new HashMap<>();
    /**
     * 自定义方法，当这个类被spring容器加载之后立即调用该方法进行资源初始化
     */
    @PostConstruct
    public void init(){
        loadResourceDefine();
    }

    private void loadResourceDefine(){
        List<Role> roles = roleService.getRoles();
        if(roles == null || roles.isEmpty()){
            LOG.warn("The role is empty, Please add the role info to db.");
            return;
        }

        for(Role role : roles){
            String roleName = role.getRoleStr();
            ConfigAttribute configAttribute = new SecurityConfig(roleName);

            Set<Resources> resources = role.getResources();
            //判断资源文件和权限的对应关系，如果已经存在相关的资源url，
            // 则要通过该url为key提取出权限集合，将权限增加到权限集合中。
            for(Resources resource : resources){
                String resourceInterceptStr = resource.getResourceInterceptStr();

                if(resourceMap.containsKey(resourceInterceptStr)){
                    Collection<ConfigAttribute> cas = resourceMap.get(resourceInterceptStr);
                    cas.add(configAttribute);
                }else{
                    Collection<ConfigAttribute> cas = new ArrayList<>();
                    cas.add(configAttribute);
                    resourceMap.put(resourceInterceptStr, cas);
                }
            }
        }
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {
        String url = ((FilterInvocation)o).getRequestUrl();
        if("/".equals(url)){
            return null;
        }

        int firstQuestionMarkIndex = url.indexOf('?');
        //判断请求是否带有参数 如果有参数就去掉后面的后缀和参数(/index.do  --> /index)
        if(firstQuestionMarkIndex != -1){
            url = url.substring(0, firstQuestionMarkIndex);
        }

        for(Map.Entry<String, Collection<ConfigAttribute>> entry : resourceMap.entrySet()){
            String resourceUrl = entry.getKey();
            //TODO 增加匹配规则
            if(url.equals(resourceUrl)){
                return entry.getValue();
            }
        }
        LOG.warn("No pattern for the url {}, Please add the pattern to db.", url);
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return null;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return true;
    }
}
